package com.fzy.core.system.service;

import ge.core.system.entity.Entity;
import ge.core.system.entity.Mapping;
import ge.core.system.entity.Property;
import ge.core.system.service.EntityListMapper;
import ge.core.system.service.MappingListMapper;
import ge.core.system.service.ModuleListMapper;
import ge.core.system.service.PropertyListMapper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fzy.core.BaseService;
import com.fzy.core.entity.Page;
import com.fzy.core.system.entity.EntityWrapper;
import com.fzy.core.system.entity.MappingWrapper;
import com.fzy.core.system.entity.PropertyWrapper;
import com.fzy.core.utils.BeanUtils;
import com.fzy.core.utils.NumberUtils;
import com.fzy.core.utils.StringUtils;
import com.opensymphony.xwork.ActionContext;

public class DbService extends BaseService {
	private static final Logger log = LoggerFactory.getLogger(DbService.class);
	MappingListMapper mappingListMapper;
	ModuleListMapper moduleListMapper;
	EntityListMapper entityListMapper;
	PropertyListMapper propertyListMapper;
	H2DbService h2DbService;
	
	public void deleteEntities (List ids){
		if(ids == null || ids.size() < 1) return ;
		for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
			String idString = (String) iterator.next();
			Long id = NumberUtils.createLongSafely(idString);
			Entity e = null;
			if(id != null)
				e = (Entity)get(Entity.class, id);
			if(e != null){
				e.setStatus("0");
				saveEntityId(e);
			}
		}
	}
	
	public EntityWrapper getEntityWrapperByEntityId(Long entityId){
		Entity entity = (Entity) getSession().get(Entity.class, entityId);
		EntityWrapper entityWrapper = new EntityWrapper();
		entityWrapper.setData(entity);
		
		List propertyWrappers = new ArrayList();
		List properties = getPropertiesByEntityId(entity.getId());
		for (Iterator iterator2 = properties.iterator(); iterator2
				.hasNext();) {
			Property property = (Property) iterator2.next();
			PropertyWrapper propertyWrapper = new PropertyWrapper();
			propertyWrapper.setData(property);
			propertyWrapper.setParent(entityWrapper);
			propertyWrappers.add(propertyWrapper);
		}
		entityWrapper.setProperties(propertyWrappers);
		return entityWrapper;
	}
	
	public List getPropertiesByEntityId(Long entityId){
		Criteria criteria = getSession().createCriteria(Property.class);
		criteria.add(Restrictions.eq("entityId", entityId))
			.add(Restrictions.eq("status", "1"));
		List result = criteria.list();
		log.debug("PARAMS:");
		log.debug("entityId:["+entityId+"]");
		log.debug("status:[1]");
		return result;
	}
	
	public List getEntitiesByMappingId(Long mappingId){
		Criteria criteria = getSession().createCriteria(Entity.class);
		criteria.add(Restrictions.eq("parentId", mappingId))
			.add(Restrictions.eq("isParentMapping", "1"))
			.add(Restrictions.eq("status", "1"));
		List result = criteria.list();
		log.debug("PARAMS:");
		log.debug("parentId:["+mappingId+"]");
		log.debug("isParentMapping:[1]");
		log.debug("status:[1]");
		return result;
	}
	
	public void addTable2mapping(Mapping mapping, Entity defaultEntity, List tableNames){
		AbstractDbService currentService = initDbService(mapping.getNameText());
		for (Iterator iterator = tableNames.iterator(); iterator.hasNext();) {
			String tableName = (String) iterator.next();
			
			Entity e = currentService.getEntityByTableName(tableName);
			BeanUtils.copyPropertiesSafely(e, defaultEntity);
			e.setParentId(mapping.getId());
			e.setIsParentMapping("1");
			
			String table = StringUtils.lowerCase(e.getTableName());
			String name = table;
			if("1".equals(e.getHasPrefix())){
				String prefix = StringUtils.lowerCase(e.getPrefixText()) + "_";
				if(!StringUtils.isBlank(prefix) && StringUtils.startsWith(table, prefix)){
					name = StringUtils.substringAfter(table, prefix);
				}
			}
			name = StringUtils.underline2camel(name);
			e.setNameText(name);
			
			saveEntityId(e);
			addColumn2entity(currentService, e.getId(), tableName);
			
			// modify key name to 'id'
			EntityWrapper entityWrapper = getEntityWrapperByEntityId(e.getId());
			if(entityWrapper.getHasId()){
				PropertyWrapper propertyWrapper = (PropertyWrapper)entityWrapper.getKeyProperties().get(0);
				Property p = propertyWrapper.getData();
				p.setNameText("id");
				saveEntityId(p);
			}
		}
	}
	
	public void addColumn2entity(AbstractDbService currentService, Long entityId, String tableName){
		List properties = currentService.getPropertiesByTableName(tableName);
		for (Iterator iterator = properties.iterator(); iterator.hasNext();) {
			Property p = (Property) iterator.next();
			p.setEntityId(entityId);
			saveEntityId(p);
		}
	}
	
	public Page listMapping(MappingQuery mappingQuery, Page page){
		List params = new LinkedList();
		String sql = "select * from t_mapping where status = '1'";
		String orders = "";
		sql += orders;
		return queryPage(sql, null, mappingListMapper, page);
	}
	
	public List getMappings(){
		List params = new LinkedList();
		String sql = "select * from t_mapping where status = '1'";
		String orders = "";
		sql += orders;
		return query(sql, params.toArray(), mappingListMapper);
	}
	
	public Page listEntity(Long mappingId, EntityQuery entityQuery, Page page){
		List params = new LinkedList();
		String sql = "select * from t_entity where status = '1' and is_parent_mapping = '1'";
		sql += getConditionSql(mappingId, "parent_id =", params);
		String orders = "";
		orders += getOrderSql("tableName", "table_name", page);
		sql += orders;
		return queryPage(sql, params.toArray(), entityListMapper, page);
	}
	
	public Page listModule(ModuleQuery moduleQuery, Page page){
		List params = new LinkedList();
		String sql = "select * from t_module where status = '1'";
		String orders = "";
		sql += orders;
		return queryPage(sql, params.toArray(), moduleListMapper, page);
	}
	
	public Page listProperty(PropertyQuery propertyQuery, Page page){
		List params = new LinkedList();
		String sql = "select * from t_property where status = '1'";
		String orders = "";
		sql += orders;
		return queryPage(sql, params.toArray(), propertyListMapper, page);
	}
	
	public Entity findEntityByTableNameAndMappingId(String tableName, Long mappingId){
		if (StringUtils.isBlank(tableName) || mappingId == null)
			return null;
		Criteria criteria = getSession().createCriteria(Entity.class);
		criteria.add(Restrictions.eq("tableName", tableName))
			.add(Restrictions.eq("parentId", mappingId))
			.add(Restrictions.eq("isParentMapping", "1"));
		Entity result = (Entity)criteria.uniqueResult();
		return result;
	}

	
	public EntityWrapper initEntityWrapper(){
		EntityWrapper entityWrapper = null;
		String namespace = ActionContext.getContext().getActionInvocation().getProxy().getNamespace();
		// namespace like /mapping/zhx/dictEntry/list.do
		// or /mapping/zhx/tables/t_dict_entry/list.do
		
		String[] x = namespace.substring(1).split("\\/");
		String mappingName = x[1];
		String xName = x[2];
		if (StringUtils.isBlank(mappingName) || StringUtils.isBlank(xName))
			return null;
		
		if("tables".equals(xName)){
			String tableName = x[3];
			AbstractDbService currentService = initDbService(mappingName);
			
			entityWrapper = new EntityWrapper();
			Entity entity = currentService.getEntityByTableName(tableName);
			entityWrapper.setData(entity);
			List propertyWrapperList = new ArrayList();
			List propertyList = currentService.getPropertiesByTableName(tableName);
			for (Iterator iterator = propertyList.iterator(); iterator.hasNext();) {
				Property p = (Property) iterator.next();
				PropertyWrapper pw = new PropertyWrapper();
				pw.setData(p);
				pw.setParent(entityWrapper);
				propertyWrapperList.add(pw);
			}
			entityWrapper.setProperties(propertyWrapperList);
		}else{
			Criteria criteria = getSession().createCriteria(Mapping.class);
			Mapping mapping = (Mapping)criteria.add(Restrictions.eq("nameText", mappingName))
					.add(Restrictions.eq("status", "1")).uniqueResult();
			if(mapping == null) return null;
			
			criteria = getSession().createCriteria(Entity.class);
			criteria.add(Restrictions.eq("nameText", xName))
				.add(Restrictions.eq("parentId", mapping.getId()))
				.add(Restrictions.eq("isParentMapping", "1"))
				.add(Restrictions.eq("status", "1"));
			Entity entity = (Entity)criteria.uniqueResult();
			
			if(entity != null){
				entityWrapper = getEntityWrapperByEntityId(entity.getId());
				MappingWrapper mappingWrapper = new MappingWrapper();
				mappingWrapper.setData(mapping);
				entityWrapper.setMapping(mappingWrapper);
			}
		}
		return entityWrapper;
	}
	
//	public Entity findEntityByMapingNameAndEntityName(String mappingName, String entityName){
//		if (StringUtils.isBlank(mappingName) || StringUtils.isBlank(entityName))
//			return null;
//		Criteria criteria = getSession().createCriteria(Mapping.class);
//		Mapping mapping = (Mapping)criteria.add(Restrictions.eq("nameText", mappingName))
//				.add(Restrictions.eq("status", "1")).uniqueResult();
//		if(mapping == null) return null;
//		criteria = getSession().createCriteria(Entity.class);
//		criteria.add(Restrictions.eq("nameText", entityName))
//			.add(Restrictions.eq("parentId", mapping.getId()))
//			.add(Restrictions.eq("isParentMapping", "1"))
//			.add(Restrictions.eq("status", "1"));
//		Entity result = (Entity)criteria.uniqueResult();
//		return result;
//	}

//	public EntityWrapper createEntityWrapperByTable(String tableName) {
//		EntityWrapper result = new EntityWrapper();
//		Entity entity = defaultDbService.getDefaultEntityByTableName(tableName);
//		result.setData(entity);
//		List propertyWrapperList = new ArrayList();
//		List propertyList = defaultDbService.getPropertiesByTable(tableName);
//		for (Iterator iterator = propertyList.iterator(); iterator.hasNext();) {
//			Property p = (Property) iterator.next();
//			PropertyWrapper pw = new PropertyWrapper();
//			pw.setData(p);
//			pw.setParent(result);
//			propertyWrapperList.add(pw);
//		}
//		result.setProperties(propertyWrapperList);
//		return result;
//	}

	public void setMappingListMapper(MappingListMapper mappingListMapper) {
		this.mappingListMapper = mappingListMapper;
	}

	public void setModuleListMapper(ModuleListMapper moduleListMapper) {
		this.moduleListMapper = moduleListMapper;
	}

	public void setEntityListMapper(EntityListMapper entityListMapper) {
		this.entityListMapper = entityListMapper;
	}

	public void setPropertyListMapper(PropertyListMapper propertyListMapper) {
		this.propertyListMapper = propertyListMapper;
	}

	public Page getTables(Mapping mapping, EntityQuery entityQuery, Page page) {
		AbstractDbService currentService = initDbService2(mapping);
		if(currentService != null)
			return currentService.getEntitiesFromTables(entityQuery, page);
		else 
			return page;
	}
	
	private AbstractDbService initDbService2(Mapping mapping) {
		AbstractDbService currentService = h2DbService;
		if (mapping == null)
			return currentService;
		
		// jndi first
		if(!StringUtils.isBlank(mapping.getJndiText())){
			currentService = DbServiceFactory.getDbService(mapping.getJdbcDriver(), mapping.getJndiText());
		}else if(!StringUtils.isBlank(mapping.getJdbcDriver())
				&& !StringUtils.isBlank(mapping.getJdbcUrl())
				&& !StringUtils.isBlank(mapping.getJdbcUsername())
				&& !StringUtils.isBlank(mapping.getJdbcPassword())
				){
			currentService = DbServiceFactory.getDbService(mapping.getJdbcDriver(), mapping.getJdbcUrl(), mapping.getJdbcUsername(), mapping.getJdbcPassword());
		}
		return currentService;
	}
	
	private AbstractDbService initDbService(String mappingName) {
//		String namespace = ActionContext.getContext().getActionInvocation()
//				.getProxy().getNamespace();
//		// namespace like /mapping/zhx/dictEntry/list.do
//		// or /mapping/zhx/tables/t_dict_entry/list.do
//
//		String[] x = namespace.substring(1).split("\\/");
//		String mappingName = x[1];
		AbstractDbService currentService = h2DbService;
		if (StringUtils.isBlank(mappingName))
			return currentService;
		Criteria criteria = getSession().createCriteria(Mapping.class);
		Mapping mapping = (Mapping) criteria
				.add(Restrictions.eq("nameText", mappingName))
				.add(Restrictions.eq("status", "1")).uniqueResult();
		if (mapping == null)
			return currentService;
		
		// jndi first
		if(!StringUtils.isBlank(mapping.getJndiText())){
			currentService = DbServiceFactory.getDbService(mapping.getJdbcDriver(), mapping.getJndiText());
		}else if(!StringUtils.isBlank(mapping.getJdbcDriver())
				&& !StringUtils.isBlank(mapping.getJdbcUrl())
				&& !StringUtils.isBlank(mapping.getJdbcUsername())
				&& !StringUtils.isBlank(mapping.getJdbcPassword())
				){
			currentService = DbServiceFactory.getDbService(mapping.getJdbcDriver(), mapping.getJdbcUrl(), mapping.getJdbcUsername(), mapping.getJdbcPassword());
		}
		return currentService;
	}

	public Map getEntityData(EntityWrapper entityWrapper,
			HttpServletRequest request) {
		String mappingName = null;
		if(entityWrapper.getMapping() != null && entityWrapper.getMapping().getData() != null)
			mappingName = entityWrapper.getMapping().getData().getNameText();
		AbstractDbService currentService = initDbService(mappingName);
		return currentService.getEntityDataByKey(entityWrapper, request);
	}
	
	public Page queryPageByMapping(Map parameters, EntityWrapper entityWrapper,
			Page page) {
		String mappingName = null;
		if(entityWrapper.getMapping() != null && entityWrapper.getMapping().getData() != null)
			mappingName = entityWrapper.getMapping().getData().getNameText();
		AbstractDbService currentService = initDbService(mappingName);
		return currentService.getEntityDataList(parameters, entityWrapper, page);
	}
	
	public List queryByMapping(Map parameters, EntityWrapper entityWrapper) {
		String mappingName = null;
		if(entityWrapper.getMapping() != null && entityWrapper.getMapping().getData() != null)
			mappingName = entityWrapper.getMapping().getData().getNameText();
		AbstractDbService currentService = initDbService(mappingName);
		return currentService.getEntityDataList(parameters, entityWrapper);
	}

	public void saveEntityData(EntityWrapper entityWrapper, Map entityData,
			boolean isCreated) {
		String mappingName = null;
		if(entityWrapper.getMapping() != null && entityWrapper.getMapping().getData() != null)
			mappingName = entityWrapper.getMapping().getData().getNameText();
		AbstractDbService currentService = initDbService(mappingName);
		currentService.saveEntityData(entityWrapper, entityData, isCreated);
	}

	public void setH2DbService(H2DbService h2DbService) {
		this.h2DbService = h2DbService;
	}
	
}
